using System;
using System.Collections.Generic;
using System.Linq;
using BSDS.Core.Model;
using BSDS.Core.Model.Data;

namespace BSDS.Core.Data.Local.Csv.Parsing
{
    public class CsvEntityParser
    {
        public EntityValue FromCsv(AttributeInfo[] attributeInfos, string valueLine, CsvSeparator separator)
        {
            string[] lineParts;

            if (separator == CsvSeparator.Comma)
            {
                lineParts = SplitLineWithCommaQuotationHandling(valueLine);
            }
            else
            {
                lineParts = valueLine.Split(new[] { separator.Value }, StringSplitOptions.None);
            }

             List<AttributeValue> attributes = lineParts.Select((t, i) => new AttributeValue(attributeInfos[i], t)).ToList();

            return new EntityValue(attributes);
        }

        private static string[] SplitLineWithCommaQuotationHandling(string valueLine)
        {
            var commaIndices = FindCommaIndicesOutsideQuotation(valueLine);

            if (commaIndices.Count == 0)
            {
                return new[] { valueLine };
            }

            var lineParts = SplitTheLine(valueLine, commaIndices);

            return RemoveQuotationsAroundParts(lineParts);
        }

        private static string[] RemoveQuotationsAroundParts(IEnumerable<string> lineParts)
        {
            var partsWithoutQuotes = new List<string>();

            foreach (var linePart in lineParts)
            {
                var part = linePart;
                if (part.StartsWith("\""))
                {
                    part = part.Substring(1, part.Length - 1);
                }
                if (part.EndsWith("\""))
                {
                    part = part.Substring(0, part.Length - 1);
                }

                partsWithoutQuotes.Add(part);
            }

            return partsWithoutQuotes.ToArray();
        }

        private static IEnumerable<string> SplitTheLine(string valueLine, IEnumerable<int> comaIndices)
        {
            var lineParts = new List<string>();
            var startIndex = 0;

            foreach (var comaIndex in comaIndices)
            {
                lineParts.Add(valueLine.Substring(startIndex, comaIndex - startIndex));
                startIndex = comaIndex + 1;
            }

            lineParts.Add(valueLine.Substring(startIndex, valueLine.Length - startIndex));

            return lineParts.ToArray();
        }

        private static List<int> FindCommaIndicesOutsideQuotation(string valueLine)
        {
            var charLine = valueLine.ToCharArray();
            var insideQuote = false;
            var comaIndices = new List<int>();

            for (int i = 0; i < charLine.Length; i++)
            {
                if (charLine[i] == '"')
                {
                    insideQuote = !insideQuote;
                }
                else if (charLine[i] == ',' && !insideQuote)
                {
                    comaIndices.Add(i);
                }
            }

            return comaIndices;
        }
    }
}